jquery-ui-timepicker-addon.js ➔ selected   B
last analyzed

Complexity

Conditions 6

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 11
dl 0
loc 18
rs 8.6666
c 0
b 0
f 0
1
/*! jQuery Timepicker Addon - v1.6.1 - 2015-11-14
2
* http://trentrichardson.com/examples/timepicker
3
* Copyright (c) 2015 Trent Richardson; Licensed MIT */
4
(function (factory) {
5
	if (typeof define === 'function' && define.amd) {
6
		define(['jquery', 'jquery-ui'], factory);
7
	} else {
8
		factory(jQuery);
9
	}
10
}(function ($) {
11
12
	/*
13
	* Lets not redefine timepicker, Prevent "Uncaught RangeError: Maximum call stack size exceeded"
14
	*/
15
	$.ui.timepicker = $.ui.timepicker || {};
16
	if ($.ui.timepicker.version) {
17
		return;
18
	}
19
20
	/*
21
	* Extend jQueryUI, get it started with our version number
22
	*/
23
	$.extend($.ui, {
24
		timepicker: {
25
			version: "1.6.1"
26
		}
27
	});
28
29
	/* 
30
	* Timepicker manager.
31
	* Use the singleton instance of this class, $.timepicker, to interact with the time picker.
32
	* Settings for (groups of) time pickers are maintained in an instance object,
33
	* allowing multiple different settings on the same page.
34
	*/
35
	var Timepicker = function () {
36
		this.regional = []; // Available regional settings, indexed by language code
37
		this.regional[''] = { // Default regional settings
38
			currentText: 'Now',
39
			closeText: 'Done',
40
			amNames: ['AM', 'A'],
41
			pmNames: ['PM', 'P'],
42
			timeFormat: 'HH:mm',
43
			timeSuffix: '',
44
			timeOnlyTitle: 'Choose Time',
45
			timeText: 'Time',
46
			hourText: 'Hour',
47
			minuteText: 'Minute',
48
			secondText: 'Second',
49
			millisecText: 'Millisecond',
50
			microsecText: 'Microsecond',
51
			timezoneText: 'Time Zone',
52
			isRTL: false
53
		};
54
		this._defaults = { // Global defaults for all the datetime picker instances
55
			showButtonPanel: true,
56
			timeOnly: false,
57
			timeOnlyShowDate: false,
58
			showHour: null,
59
			showMinute: null,
60
			showSecond: null,
61
			showMillisec: null,
62
			showMicrosec: null,
63
			showTimezone: null,
64
			showTime: true,
65
			stepHour: 1,
66
			stepMinute: 1,
67
			stepSecond: 1,
68
			stepMillisec: 1,
69
			stepMicrosec: 1,
70
			hour: 0,
71
			minute: 0,
72
			second: 0,
73
			millisec: 0,
74
			microsec: 0,
75
			timezone: null,
76
			hourMin: 0,
77
			minuteMin: 0,
78
			secondMin: 0,
79
			millisecMin: 0,
80
			microsecMin: 0,
81
			hourMax: 23,
82
			minuteMax: 59,
83
			secondMax: 59,
84
			millisecMax: 999,
85
			microsecMax: 999,
86
			minDateTime: null,
87
			maxDateTime: null,
88
			maxTime: null,
89
			minTime: null,
90
			onSelect: null,
91
			hourGrid: 0,
92
			minuteGrid: 0,
93
			secondGrid: 0,
94
			millisecGrid: 0,
95
			microsecGrid: 0,
96
			alwaysSetTime: true,
97
			separator: ' ',
98
			altFieldTimeOnly: true,
99
			altTimeFormat: null,
100
			altSeparator: null,
101
			altTimeSuffix: null,
102
			altRedirectFocus: true,
103
			pickerTimeFormat: null,
104
			pickerTimeSuffix: null,
105
			showTimepicker: true,
106
			timezoneList: null,
107
			addSliderAccess: false,
108
			sliderAccessArgs: null,
109
			controlType: 'slider',
110
			oneLine: false,
111
			defaultValue: null,
112
			parse: 'strict',
113
			afterInject: null
114
		};
115
		$.extend(this._defaults, this.regional['']);
116
	};
117
118
	$.extend(Timepicker.prototype, {
119
		$input: null,
120
		$altInput: null,
121
		$timeObj: null,
122
		inst: null,
123
		hour_slider: null,
124
		minute_slider: null,
125
		second_slider: null,
126
		millisec_slider: null,
127
		microsec_slider: null,
128
		timezone_select: null,
129
		maxTime: null,
130
		minTime: null,
131
		hour: 0,
132
		minute: 0,
133
		second: 0,
134
		millisec: 0,
135
		microsec: 0,
136
		timezone: null,
137
		hourMinOriginal: null,
138
		minuteMinOriginal: null,
139
		secondMinOriginal: null,
140
		millisecMinOriginal: null,
141
		microsecMinOriginal: null,
142
		hourMaxOriginal: null,
143
		minuteMaxOriginal: null,
144
		secondMaxOriginal: null,
145
		millisecMaxOriginal: null,
146
		microsecMaxOriginal: null,
147
		ampm: '',
148
		formattedDate: '',
149
		formattedTime: '',
150
		formattedDateTime: '',
151
		timezoneList: null,
152
		units: ['hour', 'minute', 'second', 'millisec', 'microsec'],
153
		support: {},
154
		control: null,
155
156
		/* 
157
		* Override the default settings for all instances of the time picker.
158
		* @param  {Object} settings  object - the new settings to use as defaults (anonymous object)
159
		* @return {Object} the manager object
160
		*/
161
		setDefaults: function (settings) {
162
			extendRemove(this._defaults, settings || {});
163
			return this;
164
		},
165
166
		/*
167
		* Create a new Timepicker instance
168
		*/
169
		_newInst: function ($input, opts) {
170
			var tp_inst = new Timepicker(),
171
				inlineSettings = {},
172
				fns = {},
173
				overrides, i;
174
175
			for (var attrName in this._defaults) {
176
				if (this._defaults.hasOwnProperty(attrName)) {
177
					var attrValue = $input.attr('time:' + attrName);
178
					if (attrValue) {
179
						try {
180
							inlineSettings[attrName] = eval(attrValue);
0 ignored issues
show
Security Performance introduced by
Calls to eval are slow and potentially dangerous, especially on untrusted code. Please consider whether there is another way to achieve your goal.
Loading history...
181
						} catch (err) {
182
							inlineSettings[attrName] = attrValue;
183
						}
184
					}
185
				}
186
			}
187
188
			overrides = {
189
				beforeShow: function (input, dp_inst) {
190
					if ($.isFunction(tp_inst._defaults.evnts.beforeShow)) {
191
						return tp_inst._defaults.evnts.beforeShow.call($input[0], input, dp_inst, tp_inst);
192
					}
193
				},
194
				onChangeMonthYear: function (year, month, dp_inst) {
195
					// Update the time as well : this prevents the time from disappearing from the $input field.
196
					// tp_inst._updateDateTime(dp_inst);
197
					if ($.isFunction(tp_inst._defaults.evnts.onChangeMonthYear)) {
198
						tp_inst._defaults.evnts.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst);
199
					}
200
				},
201
				onClose: function (dateText, dp_inst) {
202
					if (tp_inst.timeDefined === true && $input.val() !== '') {
203
						tp_inst._updateDateTime(dp_inst);
204
					}
205
					if ($.isFunction(tp_inst._defaults.evnts.onClose)) {
206
						tp_inst._defaults.evnts.onClose.call($input[0], dateText, dp_inst, tp_inst);
207
					}
208
				}
209
			};
210
			for (i in overrides) {
211
				if (overrides.hasOwnProperty(i)) {
212
					fns[i] = opts[i] || this._defaults[i] || null;
213
				}
214
			}
215
216
			tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, opts, overrides, {
217
				evnts: fns,
218
				timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker');
219
			});
220
			tp_inst.amNames = $.map(tp_inst._defaults.amNames, function (val) {
221
				return val.toUpperCase();
222
			});
223
			tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function (val) {
224
				return val.toUpperCase();
225
			});
226
227
			// detect which units are supported
228
			tp_inst.support = detectSupport(
229
					tp_inst._defaults.timeFormat + 
230
					(tp_inst._defaults.pickerTimeFormat ? tp_inst._defaults.pickerTimeFormat : '') +
231
					(tp_inst._defaults.altTimeFormat ? tp_inst._defaults.altTimeFormat : ''));
232
233
			// controlType is string - key to our this._controls
234
			if (typeof(tp_inst._defaults.controlType) === 'string') {
235
				if (tp_inst._defaults.controlType === 'slider' && typeof($.ui.slider) === 'undefined') {
236
					tp_inst._defaults.controlType = 'select';
237
				}
238
				tp_inst.control = tp_inst._controls[tp_inst._defaults.controlType];
239
			}
240
			// controlType is an object and must implement create, options, value methods
241
			else {
242
				tp_inst.control = tp_inst._defaults.controlType;
243
			}
244
245
			// prep the timezone options
246
			var timezoneList = [-720, -660, -600, -570, -540, -480, -420, -360, -300, -270, -240, -210, -180, -120, -60,
247
					0, 60, 120, 180, 210, 240, 270, 300, 330, 345, 360, 390, 420, 480, 525, 540, 570, 600, 630, 660, 690, 720, 765, 780, 840];
248
			if (tp_inst._defaults.timezoneList !== null) {
249
				timezoneList = tp_inst._defaults.timezoneList;
250
			}
251
			var tzl = timezoneList.length, tzi = 0, tzv = null;
252
			if (tzl > 0 && typeof timezoneList[0] !== 'object') {
253
				for (; tzi < tzl; tzi++) {
254
					tzv = timezoneList[tzi];
255
					timezoneList[tzi] = { value: tzv, label: $.timepicker.timezoneOffsetString(tzv, tp_inst.support.iso8601) };
256
				}
257
			}
258
			tp_inst._defaults.timezoneList = timezoneList;
259
260
			// set the default units
261
			tp_inst.timezone = tp_inst._defaults.timezone !== null ? $.timepicker.timezoneOffsetNumber(tp_inst._defaults.timezone) :
262
							((new Date()).getTimezoneOffset() * -1);
263
			tp_inst.hour = tp_inst._defaults.hour < tp_inst._defaults.hourMin ? tp_inst._defaults.hourMin :
264
							tp_inst._defaults.hour > tp_inst._defaults.hourMax ? tp_inst._defaults.hourMax : tp_inst._defaults.hour;
265
			tp_inst.minute = tp_inst._defaults.minute < tp_inst._defaults.minuteMin ? tp_inst._defaults.minuteMin :
266
							tp_inst._defaults.minute > tp_inst._defaults.minuteMax ? tp_inst._defaults.minuteMax : tp_inst._defaults.minute;
267
			tp_inst.second = tp_inst._defaults.second < tp_inst._defaults.secondMin ? tp_inst._defaults.secondMin :
268
							tp_inst._defaults.second > tp_inst._defaults.secondMax ? tp_inst._defaults.secondMax : tp_inst._defaults.second;
269
			tp_inst.millisec = tp_inst._defaults.millisec < tp_inst._defaults.millisecMin ? tp_inst._defaults.millisecMin :
270
							tp_inst._defaults.millisec > tp_inst._defaults.millisecMax ? tp_inst._defaults.millisecMax : tp_inst._defaults.millisec;
271
			tp_inst.microsec = tp_inst._defaults.microsec < tp_inst._defaults.microsecMin ? tp_inst._defaults.microsecMin :
272
							tp_inst._defaults.microsec > tp_inst._defaults.microsecMax ? tp_inst._defaults.microsecMax : tp_inst._defaults.microsec;
273
			tp_inst.ampm = '';
274
			tp_inst.$input = $input;
275
276
			if (tp_inst._defaults.altField) {
277
				tp_inst.$altInput = $(tp_inst._defaults.altField);
278
				if (tp_inst._defaults.altRedirectFocus === true) {
279
					tp_inst.$altInput.css({
280
						cursor: 'pointer'
281
					}).focus(function () {
282
						$input.trigger("focus");
283
					});
284
				}
285
			}
286
287
			if (tp_inst._defaults.minDate === 0 || tp_inst._defaults.minDateTime === 0) {
288
				tp_inst._defaults.minDate = new Date();
289
			}
290
			if (tp_inst._defaults.maxDate === 0 || tp_inst._defaults.maxDateTime === 0) {
291
				tp_inst._defaults.maxDate = new Date();
292
			}
293
294
			// datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime..
295
			if (tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date) {
296
				tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime());
297
			}
298
			if (tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date) {
299
				tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime());
300
			}
301
			if (tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date) {
302
				tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime());
303
			}
304
			if (tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) {
305
				tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime());
306
			}
307
			tp_inst.$input.bind('focus', function () {
308
				tp_inst._onFocus();
309
			});
310
311
			return tp_inst;
312
		},
313
314
		/*
315
		* add our sliders to the calendar
316
		*/
317
		_addTimePicker: function (dp_inst) {
318
			var currDT = $.trim((this.$altInput && this._defaults.altFieldTimeOnly) ? this.$input.val() + ' ' + this.$altInput.val() : this.$input.val());
319
320
			this.timeDefined = this._parseTime(currDT);
321
			this._limitMinMaxDateTime(dp_inst, false);
322
			this._injectTimePicker();
323
			this._afterInject();
324
		},
325
326
		/*
327
		* parse the time string from input value or _setTime
328
		*/
329
		_parseTime: function (timeString, withDate) {
330
			if (!this.inst) {
331
				this.inst = $.datepicker._getInst(this.$input[0]);
332
			}
333
334
			if (withDate || !this._defaults.timeOnly) {
335
				var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat');
336
				try {
337
					var parseRes = parseDateTimeInternal(dp_dateFormat, this._defaults.timeFormat, timeString, $.datepicker._getFormatConfig(this.inst), this._defaults);
338
					if (!parseRes.timeObj) {
339
						return false;
340
					}
341
					$.extend(this, parseRes.timeObj);
342
				} catch (err) {
343
					$.timepicker.log("Error parsing the date/time string: " + err +
344
									"\ndate/time string = " + timeString +
345
									"\ntimeFormat = " + this._defaults.timeFormat +
346
									"\ndateFormat = " + dp_dateFormat);
347
					return false;
348
				}
349
				return true;
350
			} else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
351
				var timeObj = $.datepicker.parseTime(this._defaults.timeFormat, timeString, this._defaults);
352
				if (!timeObj) {
353
					return false;
354
				}
355
				$.extend(this, timeObj);
356
				return true;
357
			}
358
		},
359
360
		/*
361
		* Handle callback option after injecting timepicker
362
		*/
363
		_afterInject: function() {
364
			var o = this.inst.settings;
365
			if ($.isFunction(o.afterInject)) {
366
				o.afterInject.call(this);
367
			}
368
		},
369
370
		/*
371
		* generate and inject html for timepicker into ui datepicker
372
		*/
373
		_injectTimePicker: function () {
374
			var $dp = this.inst.dpDiv,
375
				o = this.inst.settings,
376
				tp_inst = this,
377
				litem = '',
378
				uitem = '',
379
				show = null,
380
				max = {},
381
				gridSize = {},
382
				size = null,
383
				i = 0,
384
				l = 0;
385
386
			// Prevent displaying twice
387
			if ($dp.find("div.ui-timepicker-div").length === 0 && o.showTimepicker) {
388
				var noDisplay = ' ui_tpicker_unit_hide',
389
					html = '<div class="ui-timepicker-div' + (o.isRTL ? ' ui-timepicker-rtl' : '') + (o.oneLine && o.controlType === 'select' ? ' ui-timepicker-oneLine' : '') + '"><dl>' + '<dt class="ui_tpicker_time_label' + ((o.showTime) ? '' : noDisplay) + '">' + o.timeText + '</dt>' +
390
								'<dd class="ui_tpicker_time '+ ((o.showTime) ? '' : noDisplay) + '"><input class="ui_tpicker_time_input" ' + (o.timeInput ? '' : 'disabled') + '/></dd>';
391
392
				// Create the markup
393
				for (i = 0, l = this.units.length; i < l; i++) {
394
					litem = this.units[i];
395
					uitem = litem.substr(0, 1).toUpperCase() + litem.substr(1);
396
					show = o['show' + uitem] !== null ? o['show' + uitem] : this.support[litem];
397
398
					// Added by Peter Medeiros:
399
					// - Figure out what the hour/minute/second max should be based on the step values.
400
					// - Example: if stepMinute is 15, then minMax is 45.
401
					max[litem] = parseInt((o[litem + 'Max'] - ((o[litem + 'Max'] - o[litem + 'Min']) % o['step' + uitem])), 10);
402
					gridSize[litem] = 0;
403
404
					html += '<dt class="ui_tpicker_' + litem + '_label' + (show ? '' : noDisplay) + '">' + o[litem + 'Text'] + '</dt>' +
405
								'<dd class="ui_tpicker_' + litem + (show ? '' : noDisplay) + '"><div class="ui_tpicker_' + litem + '_slider' + (show ? '' : noDisplay) + '"></div>';
406
407
					if (show && o[litem + 'Grid'] > 0) {
408
						html += '<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>';
409
410
						if (litem === 'hour') {
411
							for (var h = o[litem + 'Min']; h <= max[litem]; h += parseInt(o[litem + 'Grid'], 10)) {
412
								gridSize[litem]++;
413
								var tmph = $.datepicker.formatTime(this.support.ampm ? 'hht' : 'HH', {hour: h}, o);
414
								html += '<td data-for="' + litem + '">' + tmph + '</td>';
415
							}
416
						}
417
						else {
418
							for (var m = o[litem + 'Min']; m <= max[litem]; m += parseInt(o[litem + 'Grid'], 10)) {
419
								gridSize[litem]++;
420
								html += '<td data-for="' + litem + '">' + ((m < 10) ? '0' : '') + m + '</td>';
421
							}
422
						}
423
424
						html += '</tr></table></div>';
425
					}
426
					html += '</dd>';
427
				}
428
				
429
				// Timezone
430
				var showTz = o.showTimezone !== null ? o.showTimezone : this.support.timezone;
431
				html += '<dt class="ui_tpicker_timezone_label' + (showTz ? '' : noDisplay) + '">' + o.timezoneText + '</dt>';
432
				html += '<dd class="ui_tpicker_timezone' + (showTz ? '' : noDisplay) + '"></dd>';
433
434
				// Create the elements from string
435
				html += '</dl></div>';
436
				var $tp = $(html);
437
438
				// if we only want time picker...
439
				if (o.timeOnly === true) {
440
					$tp.prepend('<div class="ui-widget-header ui-helper-clearfix ui-corner-all">' + '<div class="ui-datepicker-title">' + o.timeOnlyTitle + '</div>' + '</div>');
441
					$dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide();
442
				}
443
				
444
				// add sliders, adjust grids, add events
445
				for (i = 0, l = tp_inst.units.length; i < l; i++) {
446
					litem = tp_inst.units[i];
447
					uitem = litem.substr(0, 1).toUpperCase() + litem.substr(1);
448
					show = o['show' + uitem] !== null ? o['show' + uitem] : this.support[litem];
449
450
					// add the slider
451
					tp_inst[litem + '_slider'] = tp_inst.control.create(tp_inst, $tp.find('.ui_tpicker_' + litem + '_slider'), litem, tp_inst[litem], o[litem + 'Min'], max[litem], o['step' + uitem]);
452
453
					// adjust the grid and add click event
454
					if (show && o[litem + 'Grid'] > 0) {
455
						size = 100 * gridSize[litem] * o[litem + 'Grid'] / (max[litem] - o[litem + 'Min']);
456
						$tp.find('.ui_tpicker_' + litem + ' table').css({
457
							width: size + "%",
458
							marginLeft: o.isRTL ? '0' : ((size / (-2 * gridSize[litem])) + "%"),
459
							marginRight: o.isRTL ? ((size / (-2 * gridSize[litem])) + "%") : '0',
460
							borderCollapse: 'collapse'
461
						}).find("td").click(function (e) {
462
								var $t = $(this),
463
									h = $t.html(),
464
									n = parseInt(h.replace(/[^0-9]/g), 10),
465
									ap = h.replace(/[^apm]/ig),
466
									f = $t.data('for'); // loses scope, so we use data-for
467
468
								if (f === 'hour') {
469
									if (ap.indexOf('p') !== -1 && n < 12) {
470
										n += 12;
471
									}
472
									else {
473
										if (ap.indexOf('a') !== -1 && n === 12) {
474
											n = 0;
475
										}
476
									}
477
								}
478
								
479
								tp_inst.control.value(tp_inst, tp_inst[f + '_slider'], litem, n);
0 ignored issues
show
Bug introduced by
The variable litem is changed as part of the for loop for example by tp_inst.units.i on line 446. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
480
481
								tp_inst._onTimeChange();
482
								tp_inst._onSelectHandler();
483
							}).css({
484
								cursor: 'pointer',
485
								width: (100 / gridSize[litem]) + '%',
486
								textAlign: 'center',
487
								overflow: 'hidden'
488
							});
489
					} // end if grid > 0
490
				} // end for loop
491
492
				// Add timezone options
493
				this.timezone_select = $tp.find('.ui_tpicker_timezone').append('<select></select>').find("select");
494
				$.fn.append.apply(this.timezone_select,
495
				$.map(o.timezoneList, function (val, idx) {
496
					return $("<option />").val(typeof val === "object" ? val.value : val).text(typeof val === "object" ? val.label : val);
497
				}));
498
				if (typeof(this.timezone) !== "undefined" && this.timezone !== null && this.timezone !== "") {
499
					var local_timezone = (new Date(this.inst.selectedYear, this.inst.selectedMonth, this.inst.selectedDay, 12)).getTimezoneOffset() * -1;
500
					if (local_timezone === this.timezone) {
501
						selectLocalTimezone(tp_inst);
502
					} else {
503
						this.timezone_select.val(this.timezone);
504
					}
505
				} else {
506
					if (typeof(this.hour) !== "undefined" && this.hour !== null && this.hour !== "") {
507
						this.timezone_select.val(o.timezone);
508
					} else {
509
						selectLocalTimezone(tp_inst);
510
					}
511
				}
512
				this.timezone_select.change(function () {
513
					tp_inst._onTimeChange();
514
					tp_inst._onSelectHandler();
515
					tp_inst._afterInject();
516
				});
517
				// End timezone options
518
				
519
				// inject timepicker into datepicker
520
				var $buttonPanel = $dp.find('.ui-datepicker-buttonpane');
521
				if ($buttonPanel.length) {
522
					$buttonPanel.before($tp);
523
				} else {
524
					$dp.append($tp);
525
				}
526
527
				this.$timeObj = $tp.find('.ui_tpicker_time_input');
528
				this.$timeObj.change(function () {
529
					var timeFormat = tp_inst.inst.settings.timeFormat;
530
					var parsedTime = $.datepicker.parseTime(timeFormat, this.value);
531
					var update = new Date();
532
					if (parsedTime) {
533
						update.setHours(parsedTime.hour);
534
						update.setMinutes(parsedTime.minute);
535
						update.setSeconds(parsedTime.second);
536
						$.datepicker._setTime(tp_inst.inst, update);
537
					} else {
538
						this.value = tp_inst.formattedTime;
539
						this.blur();
540
					}
541
				});
542
543
				if (this.inst !== null) {
544
					var timeDefined = this.timeDefined;
545
					this._onTimeChange();
546
					this.timeDefined = timeDefined;
547
				}
548
549
				// slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/
550
				if (this._defaults.addSliderAccess) {
551
					var sliderAccessArgs = this._defaults.sliderAccessArgs,
552
						rtl = this._defaults.isRTL;
553
					sliderAccessArgs.isRTL = rtl;
554
						
555
					setTimeout(function () { // fix for inline mode
556
						if ($tp.find('.ui-slider-access').length === 0) {
557
							$tp.find('.ui-slider:visible').sliderAccess(sliderAccessArgs);
558
559
							// fix any grids since sliders are shorter
560
							var sliderAccessWidth = $tp.find('.ui-slider-access:eq(0)').outerWidth(true);
561
							if (sliderAccessWidth) {
562
								$tp.find('table:visible').each(function () {
563
									var $g = $(this),
564
										oldWidth = $g.outerWidth(),
565
										oldMarginLeft = $g.css(rtl ? 'marginRight' : 'marginLeft').toString().replace('%', ''),
566
										newWidth = oldWidth - sliderAccessWidth,
567
										newMarginLeft = ((oldMarginLeft * newWidth) / oldWidth) + '%',
568
										css = { width: newWidth, marginRight: 0, marginLeft: 0 };
569
									css[rtl ? 'marginRight' : 'marginLeft'] = newMarginLeft;
570
									$g.css(css);
571
								});
572
							}
573
						}
574
					}, 10);
575
				}
576
				// end slideAccess integration
577
578
				tp_inst._limitMinMaxDateTime(this.inst, true);
579
			}
580
		},
581
582
		/*
583
		* This function tries to limit the ability to go outside the
584
		* min/max date range
585
		*/
586
		_limitMinMaxDateTime: function (dp_inst, adjustSliders) {
587
			var o = this._defaults,
588
				dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay);
589
590
			if (!this._defaults.showTimepicker) {
591
				return;
592
			} // No time so nothing to check here
593
594
			if ($.datepicker._get(dp_inst, 'minDateTime') !== null && $.datepicker._get(dp_inst, 'minDateTime') !== undefined && dp_date) {
595
				var minDateTime = $.datepicker._get(dp_inst, 'minDateTime'),
596
					minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0);
597
598
				if (this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null || this.microsecMinOriginal === null) {
599
					this.hourMinOriginal = o.hourMin;
600
					this.minuteMinOriginal = o.minuteMin;
601
					this.secondMinOriginal = o.secondMin;
602
					this.millisecMinOriginal = o.millisecMin;
603
					this.microsecMinOriginal = o.microsecMin;
604
				}
605
606
				if (dp_inst.settings.timeOnly || minDateTimeDate.getTime() === dp_date.getTime()) {
607
					this._defaults.hourMin = minDateTime.getHours();
608
					if (this.hour <= this._defaults.hourMin) {
609
						this.hour = this._defaults.hourMin;
610
						this._defaults.minuteMin = minDateTime.getMinutes();
611
						if (this.minute <= this._defaults.minuteMin) {
612
							this.minute = this._defaults.minuteMin;
613
							this._defaults.secondMin = minDateTime.getSeconds();
614
							if (this.second <= this._defaults.secondMin) {
615
								this.second = this._defaults.secondMin;
616
								this._defaults.millisecMin = minDateTime.getMilliseconds();
617
								if (this.millisec <= this._defaults.millisecMin) {
618
									this.millisec = this._defaults.millisecMin;
619
									this._defaults.microsecMin = minDateTime.getMicroseconds();
620
								} else {
621
									if (this.microsec < this._defaults.microsecMin) {
622
										this.microsec = this._defaults.microsecMin;
623
									}
624
									this._defaults.microsecMin = this.microsecMinOriginal;
625
								}
626
							} else {
627
								this._defaults.millisecMin = this.millisecMinOriginal;
628
								this._defaults.microsecMin = this.microsecMinOriginal;
629
							}
630
						} else {
631
							this._defaults.secondMin = this.secondMinOriginal;
632
							this._defaults.millisecMin = this.millisecMinOriginal;
633
							this._defaults.microsecMin = this.microsecMinOriginal;
634
						}
635
					} else {
636
						this._defaults.minuteMin = this.minuteMinOriginal;
637
						this._defaults.secondMin = this.secondMinOriginal;
638
						this._defaults.millisecMin = this.millisecMinOriginal;
639
						this._defaults.microsecMin = this.microsecMinOriginal;
640
					}
641
				} else {
642
					this._defaults.hourMin = this.hourMinOriginal;
643
					this._defaults.minuteMin = this.minuteMinOriginal;
644
					this._defaults.secondMin = this.secondMinOriginal;
645
					this._defaults.millisecMin = this.millisecMinOriginal;
646
					this._defaults.microsecMin = this.microsecMinOriginal;
647
				}
648
			}
649
650
			if ($.datepicker._get(dp_inst, 'maxDateTime') !== null && $.datepicker._get(dp_inst, 'maxDateTime') !== undefined && dp_date) {
651
				var maxDateTime = $.datepicker._get(dp_inst, 'maxDateTime'),
652
					maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0);
653
654
				if (this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null || this.millisecMaxOriginal === null) {
655
					this.hourMaxOriginal = o.hourMax;
656
					this.minuteMaxOriginal = o.minuteMax;
657
					this.secondMaxOriginal = o.secondMax;
658
					this.millisecMaxOriginal = o.millisecMax;
659
					this.microsecMaxOriginal = o.microsecMax;
660
				}
661
662
				if (dp_inst.settings.timeOnly || maxDateTimeDate.getTime() === dp_date.getTime()) {
663
					this._defaults.hourMax = maxDateTime.getHours();
664
					if (this.hour >= this._defaults.hourMax) {
665
						this.hour = this._defaults.hourMax;
666
						this._defaults.minuteMax = maxDateTime.getMinutes();
667
						if (this.minute >= this._defaults.minuteMax) {
668
							this.minute = this._defaults.minuteMax;
669
							this._defaults.secondMax = maxDateTime.getSeconds();
670
							if (this.second >= this._defaults.secondMax) {
671
								this.second = this._defaults.secondMax;
672
								this._defaults.millisecMax = maxDateTime.getMilliseconds();
673
								if (this.millisec >= this._defaults.millisecMax) {
674
									this.millisec = this._defaults.millisecMax;
675
									this._defaults.microsecMax = maxDateTime.getMicroseconds();
676
								} else {
677
									if (this.microsec > this._defaults.microsecMax) {
678
										this.microsec = this._defaults.microsecMax;
679
									}
680
									this._defaults.microsecMax = this.microsecMaxOriginal;
681
								}
682
							} else {
683
								this._defaults.millisecMax = this.millisecMaxOriginal;
684
								this._defaults.microsecMax = this.microsecMaxOriginal;
685
							}
686
						} else {
687
							this._defaults.secondMax = this.secondMaxOriginal;
688
							this._defaults.millisecMax = this.millisecMaxOriginal;
689
							this._defaults.microsecMax = this.microsecMaxOriginal;
690
						}
691
					} else {
692
						this._defaults.minuteMax = this.minuteMaxOriginal;
693
						this._defaults.secondMax = this.secondMaxOriginal;
694
						this._defaults.millisecMax = this.millisecMaxOriginal;
695
						this._defaults.microsecMax = this.microsecMaxOriginal;
696
					}
697
				} else {
698
					this._defaults.hourMax = this.hourMaxOriginal;
699
					this._defaults.minuteMax = this.minuteMaxOriginal;
700
					this._defaults.secondMax = this.secondMaxOriginal;
701
					this._defaults.millisecMax = this.millisecMaxOriginal;
702
					this._defaults.microsecMax = this.microsecMaxOriginal;
703
				}
704
			}
705
706
			if (dp_inst.settings.minTime!==null) {				
707
				var tempMinTime=new Date("01/01/1970 " + dp_inst.settings.minTime);				
708
				if (this.hour<tempMinTime.getHours()) {
709
					this.hour=this._defaults.hourMin=tempMinTime.getHours();
710
					this.minute=this._defaults.minuteMin=tempMinTime.getMinutes();							
711
				} else if (this.hour===tempMinTime.getHours() && this.minute<tempMinTime.getMinutes()) {
712
					this.minute=this._defaults.minuteMin=tempMinTime.getMinutes();
713
				} else {						
714
					if (this._defaults.hourMin<tempMinTime.getHours()) {
715
						this._defaults.hourMin=tempMinTime.getHours();
716
						this._defaults.minuteMin=tempMinTime.getMinutes();					
717
					} else if (this._defaults.hourMin===tempMinTime.getHours()===this.hour && this._defaults.minuteMin<tempMinTime.getMinutes()) {
718
						this._defaults.minuteMin=tempMinTime.getMinutes();						
719
					} else {
720
						this._defaults.minuteMin=0;
721
					}
722
				}				
723
			}
724
			
725
			if (dp_inst.settings.maxTime!==null) {				
726
				var tempMaxTime=new Date("01/01/1970 " + dp_inst.settings.maxTime);
727
				if (this.hour>tempMaxTime.getHours()) {
728
					this.hour=this._defaults.hourMax=tempMaxTime.getHours();						
729
					this.minute=this._defaults.minuteMax=tempMaxTime.getMinutes();
730
				} else if (this.hour===tempMaxTime.getHours() && this.minute>tempMaxTime.getMinutes()) {							
731
					this.minute=this._defaults.minuteMax=tempMaxTime.getMinutes();						
732
				} else {
733
					if (this._defaults.hourMax>tempMaxTime.getHours()) {
734
						this._defaults.hourMax=tempMaxTime.getHours();
735
						this._defaults.minuteMax=tempMaxTime.getMinutes();					
736
					} else if (this._defaults.hourMax===tempMaxTime.getHours()===this.hour && this._defaults.minuteMax>tempMaxTime.getMinutes()) {
737
						this._defaults.minuteMax=tempMaxTime.getMinutes();						
738
					} else {
739
						this._defaults.minuteMax=59;
740
					}
741
				}						
742
			}
743
			
744
			if (adjustSliders !== undefined && adjustSliders === true) {
745
				var hourMax = parseInt((this._defaults.hourMax - ((this._defaults.hourMax - this._defaults.hourMin) % this._defaults.stepHour)), 10),
746
					minMax = parseInt((this._defaults.minuteMax - ((this._defaults.minuteMax - this._defaults.minuteMin) % this._defaults.stepMinute)), 10),
747
					secMax = parseInt((this._defaults.secondMax - ((this._defaults.secondMax - this._defaults.secondMin) % this._defaults.stepSecond)), 10),
748
					millisecMax = parseInt((this._defaults.millisecMax - ((this._defaults.millisecMax - this._defaults.millisecMin) % this._defaults.stepMillisec)), 10),
749
					microsecMax = parseInt((this._defaults.microsecMax - ((this._defaults.microsecMax - this._defaults.microsecMin) % this._defaults.stepMicrosec)), 10);
750
751
				if (this.hour_slider) {
752
					this.control.options(this, this.hour_slider, 'hour', { min: this._defaults.hourMin, max: hourMax, step: this._defaults.stepHour });
753
					this.control.value(this, this.hour_slider, 'hour', this.hour - (this.hour % this._defaults.stepHour));
754
				}
755
				if (this.minute_slider) {
756
					this.control.options(this, this.minute_slider, 'minute', { min: this._defaults.minuteMin, max: minMax, step: this._defaults.stepMinute });
757
					this.control.value(this, this.minute_slider, 'minute', this.minute - (this.minute % this._defaults.stepMinute));
758
				}
759
				if (this.second_slider) {
760
					this.control.options(this, this.second_slider, 'second', { min: this._defaults.secondMin, max: secMax, step: this._defaults.stepSecond });
761
					this.control.value(this, this.second_slider, 'second', this.second - (this.second % this._defaults.stepSecond));
762
				}
763
				if (this.millisec_slider) {
764
					this.control.options(this, this.millisec_slider, 'millisec', { min: this._defaults.millisecMin, max: millisecMax, step: this._defaults.stepMillisec });
765
					this.control.value(this, this.millisec_slider, 'millisec', this.millisec - (this.millisec % this._defaults.stepMillisec));
766
				}
767
				if (this.microsec_slider) {
768
					this.control.options(this, this.microsec_slider, 'microsec', { min: this._defaults.microsecMin, max: microsecMax, step: this._defaults.stepMicrosec });
769
					this.control.value(this, this.microsec_slider, 'microsec', this.microsec - (this.microsec % this._defaults.stepMicrosec));
770
				}
771
			}
772
773
		},
774
775
		/*
776
		* when a slider moves, set the internal time...
777
		* on time change is also called when the time is updated in the text field
778
		*/
779
		_onTimeChange: function () {
780
			if (!this._defaults.showTimepicker) {
781
                                return;
782
			}
783
			var hour = (this.hour_slider) ? this.control.value(this, this.hour_slider, 'hour') : false,
784
				minute = (this.minute_slider) ? this.control.value(this, this.minute_slider, 'minute') : false,
785
				second = (this.second_slider) ? this.control.value(this, this.second_slider, 'second') : false,
786
				millisec = (this.millisec_slider) ? this.control.value(this, this.millisec_slider, 'millisec') : false,
787
				microsec = (this.microsec_slider) ? this.control.value(this, this.microsec_slider, 'microsec') : false,
788
				timezone = (this.timezone_select) ? this.timezone_select.val() : false,
789
				o = this._defaults,
790
				pickerTimeFormat = o.pickerTimeFormat || o.timeFormat,
791
				pickerTimeSuffix = o.pickerTimeSuffix || o.timeSuffix;
792
793
			if (typeof(hour) === 'object') {
794
				hour = false;
795
			}
796
			if (typeof(minute) === 'object') {
797
				minute = false;
798
			}
799
			if (typeof(second) === 'object') {
800
				second = false;
801
			}
802
			if (typeof(millisec) === 'object') {
803
				millisec = false;
804
			}
805
			if (typeof(microsec) === 'object') {
806
				microsec = false;
807
			}
808
			if (typeof(timezone) === 'object') {
809
				timezone = false;
810
			}
811
812
			if (hour !== false) {
813
				hour = parseInt(hour, 10);
814
			}
815
			if (minute !== false) {
816
				minute = parseInt(minute, 10);
817
			}
818
			if (second !== false) {
819
				second = parseInt(second, 10);
820
			}
821
			if (millisec !== false) {
822
				millisec = parseInt(millisec, 10);
823
			}
824
			if (microsec !== false) {
825
				microsec = parseInt(microsec, 10);
826
			}
827
			if (timezone !== false) {
828
				timezone = timezone.toString();
829
			}
830
831
			var ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0];
832
833
			// If the update was done in the input field, the input field should not be updated.
834
			// If the update was done using the sliders, update the input field.
835
			var hasChanged = (
836
						hour !== parseInt(this.hour,10) || // sliders should all be numeric
837
						minute !== parseInt(this.minute,10) || 
838
						second !== parseInt(this.second,10) || 
839
						millisec !== parseInt(this.millisec,10) || 
840
						microsec !== parseInt(this.microsec,10) || 
841
						(this.ampm.length > 0 && (hour < 12) !== ($.inArray(this.ampm.toUpperCase(), this.amNames) !== -1)) || 
842
						(this.timezone !== null && timezone !== this.timezone.toString()) // could be numeric or "EST" format, so use toString()
843
					);
844
845
			if (hasChanged) {
846
847
				if (hour !== false) {
848
					this.hour = hour;
849
				}
850
				if (minute !== false) {
851
					this.minute = minute;
852
				}
853
				if (second !== false) {
854
					this.second = second;
855
				}
856
				if (millisec !== false) {
857
					this.millisec = millisec;
858
				}
859
				if (microsec !== false) {
860
					this.microsec = microsec;
861
				}
862
				if (timezone !== false) {
863
					this.timezone = timezone;
864
				}
865
866
				if (!this.inst) {
867
					this.inst = $.datepicker._getInst(this.$input[0]);
868
				}
869
870
				this._limitMinMaxDateTime(this.inst, true);
871
			}
872
			if (this.support.ampm) {
873
				this.ampm = ampm;
874
			}
875
876
			// Updates the time within the timepicker
877
			this.formattedTime = $.datepicker.formatTime(o.timeFormat, this, o);
878
			if (this.$timeObj) {
879
				var sPos = this.$timeObj[0].selectionStart;
880
				var ePos = this.$timeObj[0].selectionEnd;
881
				if (pickerTimeFormat === o.timeFormat) {
882
					this.$timeObj.val(this.formattedTime + pickerTimeSuffix);
883
				}
884
				else {
885
					this.$timeObj.val($.datepicker.formatTime(pickerTimeFormat, this, o) + pickerTimeSuffix);
886
				}
887
				//this.$timeObj[0].setSelectionRange(sPos, ePos);
888
			}
889
890
			this.timeDefined = true;
891
			if (hasChanged) {
892
				this._updateDateTime();
893
				//this.$input.focus(); // may automatically open the picker on setDate
894
			}
895
		},
896
897
		/*
898
		* call custom onSelect.
899
		* bind to sliders slidestop, and grid click.
900
		*/
901
		_onSelectHandler: function () {
902
			var onSelect = this._defaults.onSelect || this.inst.settings.onSelect;
903
			var inputEl = this.$input ? this.$input[0] : null;
904
			if (onSelect && inputEl) {
905
				onSelect.apply(inputEl, [this.formattedDateTime, this]);
906
			}
907
		},
908
909
		/*
910
		* update our input with the new date time..
911
		*/
912
		_updateDateTime: function (dp_inst) {
913
			dp_inst = this.inst || dp_inst;
914
			var dtTmp = (dp_inst.currentYear > 0? 
915
							new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay) : 
916
							new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
917
				dt = $.datepicker._daylightSavingAdjust(dtTmp),
918
				//dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
919
				//dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay)),
920
				dateFmt = $.datepicker._get(dp_inst, 'dateFormat'),
921
				formatCfg = $.datepicker._getFormatConfig(dp_inst),
922
				timeAvailable = dt !== null && this.timeDefined;
923
			this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg);
924
			var formattedDateTime = this.formattedDate;
925
			
926
			// if a slider was changed but datepicker doesn't have a value yet, set it
927
			if (dp_inst.lastVal === "") {
928
                dp_inst.currentYear = dp_inst.selectedYear;
929
                dp_inst.currentMonth = dp_inst.selectedMonth;
930
                dp_inst.currentDay = dp_inst.selectedDay;
931
            }
932
933
			/*
934
			* remove following lines to force every changes in date picker to change the input value
935
			* Bug descriptions: when an input field has a default value, and click on the field to pop up the date picker. 
936
			* If the user manually empty the value in the input field, the date picker will never change selected value.
937
			*/
938
			//if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) {
939
			//	return;
940
			//}
941
942
			if (this._defaults.timeOnly === true && this._defaults.timeOnlyShowDate === false) {
943
				formattedDateTime = this.formattedTime;
944
			} else if ((this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) || (this._defaults.timeOnly === true && this._defaults.timeOnlyShowDate === true)) {
945
				formattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix;
946
			}
947
948
			this.formattedDateTime = formattedDateTime;
949
950
			if (!this._defaults.showTimepicker) {
951
				this.$input.val(this.formattedDate);
952
			} else if (this.$altInput && this._defaults.timeOnly === false && this._defaults.altFieldTimeOnly === true) {
953
				this.$altInput.val(this.formattedTime);
954
				this.$input.val(this.formattedDate);
955
			} else if (this.$altInput) {
956
				this.$input.val(formattedDateTime);
957
				var altFormattedDateTime = '',
958
					altSeparator = this._defaults.altSeparator !== null ? this._defaults.altSeparator : this._defaults.separator,
959
					altTimeSuffix = this._defaults.altTimeSuffix !== null ? this._defaults.altTimeSuffix : this._defaults.timeSuffix;
960
				
961
				if (!this._defaults.timeOnly) {
962
					if (this._defaults.altFormat) {
963
						altFormattedDateTime = $.datepicker.formatDate(this._defaults.altFormat, (dt === null ? new Date() : dt), formatCfg);
964
					}
965
					else {
966
						altFormattedDateTime = this.formattedDate;
967
					}
968
969
					if (altFormattedDateTime) {
970
						altFormattedDateTime += altSeparator;
971
					}
972
				}
973
974
				if (this._defaults.altTimeFormat !== null) {
975
					altFormattedDateTime += $.datepicker.formatTime(this._defaults.altTimeFormat, this, this._defaults) + altTimeSuffix;
976
				}
977
				else {
978
					altFormattedDateTime += this.formattedTime + altTimeSuffix;
979
				}
980
				this.$altInput.val(altFormattedDateTime);
981
			} else {
982
				this.$input.val(formattedDateTime);
983
			}
984
985
			this.$input.trigger("change");
986
		},
987
988
		_onFocus: function () {
989
			if (!this.$input.val() && this._defaults.defaultValue) {
990
				this.$input.val(this._defaults.defaultValue);
991
				var inst = $.datepicker._getInst(this.$input.get(0)),
992
					tp_inst = $.datepicker._get(inst, 'timepicker');
993
				if (tp_inst) {
994
					if (tp_inst._defaults.timeOnly && (inst.input.val() !== inst.lastVal)) {
995
						try {
996
							$.datepicker._updateDatepicker(inst);
997
						} catch (err) {
998
							$.timepicker.log(err);
999
						}
1000
					}
1001
				}
1002
			}
1003
		},
1004
1005
		/*
1006
		* Small abstraction to control types
1007
		* We can add more, just be sure to follow the pattern: create, options, value
1008
		*/
1009
		_controls: {
1010
			// slider methods
1011
			slider: {
1012
				create: function (tp_inst, obj, unit, val, min, max, step) {
1013
					var rtl = tp_inst._defaults.isRTL; // if rtl go -60->0 instead of 0->60
1014
					return obj.prop('slide', null).slider({
1015
						orientation: "horizontal",
1016
						value: rtl ? val * -1 : val,
1017
						min: rtl ? max * -1 : min,
1018
						max: rtl ? min * -1 : max,
1019
						step: step,
1020
						slide: function (event, ui) {
1021
							tp_inst.control.value(tp_inst, $(this), unit, rtl ? ui.value * -1 : ui.value);
1022
							tp_inst._onTimeChange();
1023
						},
1024
						stop: function (event, ui) {
1025
							tp_inst._onSelectHandler();
1026
						}
1027
					});	
1028
				},
1029
				options: function (tp_inst, obj, unit, opts, val) {
1030
					if (tp_inst._defaults.isRTL) {
1031
						if (typeof(opts) === 'string') {
1032
							if (opts === 'min' || opts === 'max') {
1033
								if (val !== undefined) {
1034
									return obj.slider(opts, val * -1);
1035
								}
1036
								return Math.abs(obj.slider(opts));
1037
							}
1038
							return obj.slider(opts);
1039
						}
1040
						var min = opts.min, 
1041
							max = opts.max;
1042
						opts.min = opts.max = null;
1043
						if (min !== undefined) {
1044
							opts.max = min * -1;
1045
						}
1046
						if (max !== undefined) {
1047
							opts.min = max * -1;
1048
						}
1049
						return obj.slider(opts);
1050
					}
1051
					if (typeof(opts) === 'string' && val !== undefined) {
1052
						return obj.slider(opts, val);
1053
					}
1054
					return obj.slider(opts);
1055
				},
1056
				value: function (tp_inst, obj, unit, val) {
1057
					if (tp_inst._defaults.isRTL) {
1058
						if (val !== undefined) {
1059
							return obj.slider('value', val * -1);
1060
						}
1061
						return Math.abs(obj.slider('value'));
1062
					}
1063
					if (val !== undefined) {
1064
						return obj.slider('value', val);
1065
					}
1066
					return obj.slider('value');
1067
				}
1068
			},
1069
			// select methods
1070
			select: {
1071
				create: function (tp_inst, obj, unit, val, min, max, step) {
1072
					var sel = '<select class="ui-timepicker-select ui-state-default ui-corner-all" data-unit="' + unit + '" data-min="' + min + '" data-max="' + max + '" data-step="' + step + '">',
1073
						format = tp_inst._defaults.pickerTimeFormat || tp_inst._defaults.timeFormat;
1074
1075
					for (var i = min; i <= max; i += step) {
1076
						sel += '<option value="' + i + '"' + (i === val ? ' selected' : '') + '>';
1077
						if (unit === 'hour') {
1078
							sel += $.datepicker.formatTime($.trim(format.replace(/[^ht ]/ig, '')), {hour: i}, tp_inst._defaults);
1079
						}
1080
						else if (unit === 'millisec' || unit === 'microsec' || i >= 10) { sel += i; }
1081
						else {sel += '0' + i.toString(); }
1082
						sel += '</option>';
1083
					}
1084
					sel += '</select>';
1085
1086
					obj.children('select').remove();
1087
1088
					$(sel).appendTo(obj).change(function (e) {
1089
						tp_inst._onTimeChange();
1090
						tp_inst._onSelectHandler();
1091
						tp_inst._afterInject();
1092
					});
1093
1094
					return obj;
1095
				},
1096
				options: function (tp_inst, obj, unit, opts, val) {
1097
					var o = {},
1098
						$t = obj.children('select');
1099
					if (typeof(opts) === 'string') {
1100
						if (val === undefined) {
1101
							return $t.data(opts);
1102
						}
1103
						o[opts] = val;	
1104
					}
1105
					else { o = opts; }
1106
					return tp_inst.control.create(tp_inst, obj, $t.data('unit'), $t.val(), o.min>=0 ? o.min : $t.data('min'), o.max || $t.data('max'), o.step || $t.data('step'));
1107
				},
1108
				value: function (tp_inst, obj, unit, val) {
1109
					var $t = obj.children('select');
1110
					if (val !== undefined) {
1111
						return $t.val(val);
1112
					}
1113
					return $t.val();
1114
				}
1115
			}
1116
		} // end _controls
1117
1118
	});
1119
1120
	$.fn.extend({
1121
		/*
1122
		* shorthand just to use timepicker.
1123
		*/
1124
		timepicker: function (o) {
1125
			o = o || {};
1126
			var tmp_args = Array.prototype.slice.call(arguments);
1127
1128
			if (typeof o === 'object') {
1129
				tmp_args[0] = $.extend(o, {
1130
					timeOnly: true
1131
				});
1132
			}
1133
1134
			return $(this).each(function () {
1135
				$.fn.datetimepicker.apply($(this), tmp_args);
1136
			});
1137
		},
1138
1139
		/*
1140
		* extend timepicker to datepicker
1141
		*/
1142
		datetimepicker: function (o) {
1143
			o = o || {};
1144
			var tmp_args = arguments;
1145
1146
			if (typeof(o) === 'string') {
1147
				if (o === 'getDate'  || (o === 'option' && tmp_args.length === 2 && typeof (tmp_args[1]) === 'string')) {
1148
					return $.fn.datepicker.apply($(this[0]), tmp_args);
1149
				} else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
1150
					return this.each(function () {
1151
						var $t = $(this);
1152
						$t.datepicker.apply($t, tmp_args);
1153
					});
1154
				}
1155
			} else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
1156
				return this.each(function () {
1157
					var $t = $(this);
1158
					$t.datepicker($.timepicker._newInst($t, o)._defaults);
1159
				});
1160
			}
1161
		}
1162
	});
1163
1164
	/*
1165
	* Public Utility to parse date and time
1166
	*/
1167
	$.datepicker.parseDateTime = function (dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
1168
		var parseRes = parseDateTimeInternal(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings);
1169
		if (parseRes.timeObj) {
1170
			var t = parseRes.timeObj;
1171
			parseRes.date.setHours(t.hour, t.minute, t.second, t.millisec);
1172
			parseRes.date.setMicroseconds(t.microsec);
1173
		}
1174
1175
		return parseRes.date;
1176
	};
1177
1178
	/*
1179
	* Public utility to parse time
1180
	*/
1181
	$.datepicker.parseTime = function (timeFormat, timeString, options) {
1182
		var o = extendRemove(extendRemove({}, $.timepicker._defaults), options || {}),
1183
			iso8601 = (timeFormat.replace(/\'.*?\'/g, '').indexOf('Z') !== -1);
1184
1185
		// Strict parse requires the timeString to match the timeFormat exactly
1186
		var strictParse = function (f, s, o) {
1187
1188
			// pattern for standard and localized AM/PM markers
1189
			var getPatternAmpm = function (amNames, pmNames) {
1190
				var markers = [];
1191
				if (amNames) {
1192
					$.merge(markers, amNames);
1193
				}
1194
				if (pmNames) {
1195
					$.merge(markers, pmNames);
1196
				}
1197
				markers = $.map(markers, function (val) {
1198
					return val.replace(/[.*+?|()\[\]{}\\]/g, '\\$&');
1199
				});
1200
				return '(' + markers.join('|') + ')?';
1201
			};
1202
1203
			// figure out position of time elements.. cause js cant do named captures
1204
			var getFormatPositions = function (timeFormat) {
1205
				var finds = timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|c{1}|t{1,2}|z|'.*?')/g),
1206
					orders = {
1207
						h: -1,
1208
						m: -1,
1209
						s: -1,
1210
						l: -1,
1211
						c: -1,
1212
						t: -1,
1213
						z: -1
1214
					};
1215
1216
				if (finds) {
1217
					for (var i = 0; i < finds.length; i++) {
1218
						if (orders[finds[i].toString().charAt(0)] === -1) {
1219
							orders[finds[i].toString().charAt(0)] = i + 1;
1220
						}
1221
					}
1222
				}
1223
				return orders;
1224
			};
1225
1226
			var regstr = '^' + f.toString()
1227
					.replace(/([hH]{1,2}|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function (match) {
1228
							var ml = match.length;
1229
							switch (match.charAt(0).toLowerCase()) {
1230
							case 'h':
1231
								return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})';
1232
							case 'm':
1233
								return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})';
1234
							case 's':
1235
								return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})';
1236
							case 'l':
1237
								return '(\\d?\\d?\\d)';
1238
							case 'c':
1239
								return '(\\d?\\d?\\d)';
1240
							case 'z':
1241
								return '(z|[-+]\\d\\d:?\\d\\d|\\S+)?';
1242
							case 't':
1243
								return getPatternAmpm(o.amNames, o.pmNames);
1244
							default:    // literal escaped in quotes
1245
								return '(' + match.replace(/\'/g, "").replace(/(\.|\$|\^|\\|\/|\(|\)|\[|\]|\?|\+|\*)/g, function (m) { return "\\" + m; }) + ')?';
1246
							}
1247
						})
1248
					.replace(/\s/g, '\\s?') +
1249
					o.timeSuffix + '$',
1250
				order = getFormatPositions(f),
1251
				ampm = '',
1252
				treg;
1253
1254
			treg = s.match(new RegExp(regstr, 'i'));
1255
1256
			var resTime = {
1257
				hour: 0,
1258
				minute: 0,
1259
				second: 0,
1260
				millisec: 0,
1261
				microsec: 0
1262
			};
1263
1264
			if (treg) {
1265
				if (order.t !== -1) {
1266
					if (treg[order.t] === undefined || treg[order.t].length === 0) {
1267
						ampm = '';
1268
						resTime.ampm = '';
1269
					} else {
1270
						ampm = $.inArray(treg[order.t].toUpperCase(), $.map(o.amNames, function (x,i) { return x.toUpperCase(); })) !== -1 ? 'AM' : 'PM';
1271
						resTime.ampm = o[ampm === 'AM' ? 'amNames' : 'pmNames'][0];
1272
					}
1273
				}
1274
1275
				if (order.h !== -1) {
1276
					if (ampm === 'AM' && treg[order.h] === '12') {
1277
						resTime.hour = 0; // 12am = 0 hour
1278
					} else {
1279
						if (ampm === 'PM' && treg[order.h] !== '12') {
1280
							resTime.hour = parseInt(treg[order.h], 10) + 12; // 12pm = 12 hour, any other pm = hour + 12
1281
						} else {
1282
							resTime.hour = Number(treg[order.h]);
1283
						}
1284
					}
1285
				}
1286
1287
				if (order.m !== -1) {
1288
					resTime.minute = Number(treg[order.m]);
1289
				}
1290
				if (order.s !== -1) {
1291
					resTime.second = Number(treg[order.s]);
1292
				}
1293
				if (order.l !== -1) {
1294
					resTime.millisec = Number(treg[order.l]);
1295
				}
1296
				if (order.c !== -1) {
1297
					resTime.microsec = Number(treg[order.c]);
1298
				}
1299
				if (order.z !== -1 && treg[order.z] !== undefined) {
1300
					resTime.timezone = $.timepicker.timezoneOffsetNumber(treg[order.z]);
1301
				}
1302
1303
1304
				return resTime;
1305
			}
1306
			return false;
1307
		};// end strictParse
1308
1309
		// First try JS Date, if that fails, use strictParse
1310
		var looseParse = function (f, s, o) {
1311
			try {
1312
				var d = new Date('2012-01-01 ' + s);
1313
				if (isNaN(d.getTime())) {
1314
					d = new Date('2012-01-01T' + s);
1315
					if (isNaN(d.getTime())) {
1316
						d = new Date('01/01/2012 ' + s);
1317
						if (isNaN(d.getTime())) {
1318
							throw "Unable to parse time with native Date: " + s;
1319
						}
1320
					}
1321
				}
1322
1323
				return {
1324
					hour: d.getHours(),
1325
					minute: d.getMinutes(),
1326
					second: d.getSeconds(),
1327
					millisec: d.getMilliseconds(),
1328
					microsec: d.getMicroseconds(),
1329
					timezone: d.getTimezoneOffset() * -1
1330
				};
1331
			}
1332
			catch (err) {
1333
				try {
1334
					return strictParse(f, s, o);
1335
				}
1336
				catch (err2) {
1337
					$.timepicker.log("Unable to parse \ntimeString: " + s + "\ntimeFormat: " + f);
1338
				}				
1339
			}
1340
			return false;
1341
		}; // end looseParse
1342
		
1343
		if (typeof o.parse === "function") {
1344
			return o.parse(timeFormat, timeString, o);
1345
		}
1346
		if (o.parse === 'loose') {
1347
			return looseParse(timeFormat, timeString, o);
1348
		}
1349
		return strictParse(timeFormat, timeString, o);
1350
	};
1351
1352
	/**
1353
	 * Public utility to format the time
1354
	 * @param {string} format format of the time
1355
	 * @param {Object} time Object not a Date for timezones
1356
	 * @param {Object} [options] essentially the regional[].. amNames, pmNames, ampm
1357
	 * @returns {string} the formatted time
1358
	 */
1359
	$.datepicker.formatTime = function (format, time, options) {
1360
		options = options || {};
1361
		options = $.extend({}, $.timepicker._defaults, options);
1362
		time = $.extend({
1363
			hour: 0,
1364
			minute: 0,
1365
			second: 0,
1366
			millisec: 0,
1367
			microsec: 0,
1368
			timezone: null
1369
		}, time);
1370
1371
		var tmptime = format,
1372
			ampmName = options.amNames[0],
1373
			hour = parseInt(time.hour, 10);
1374
1375
		if (hour > 11) {
1376
			ampmName = options.pmNames[0];
1377
		}
1378
1379
		tmptime = tmptime.replace(/(?:HH?|hh?|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function (match) {
1380
			switch (match) {
1381
			case 'HH':
1382
				return ('0' + hour).slice(-2);
1383
			case 'H':
1384
				return hour;
1385
			case 'hh':
1386
				return ('0' + convert24to12(hour)).slice(-2);
1387
			case 'h':
1388
				return convert24to12(hour);
1389
			case 'mm':
1390
				return ('0' + time.minute).slice(-2);
1391
			case 'm':
1392
				return time.minute;
1393
			case 'ss':
1394
				return ('0' + time.second).slice(-2);
1395
			case 's':
1396
				return time.second;
1397
			case 'l':
1398
				return ('00' + time.millisec).slice(-3);
1399
			case 'c':
1400
				return ('00' + time.microsec).slice(-3);
1401
			case 'z':
1402
				return $.timepicker.timezoneOffsetString(time.timezone === null ? options.timezone : time.timezone, false);
1403
			case 'Z':
1404
				return $.timepicker.timezoneOffsetString(time.timezone === null ? options.timezone : time.timezone, true);
1405
			case 'T':
1406
				return ampmName.charAt(0).toUpperCase();
1407
			case 'TT':
1408
				return ampmName.toUpperCase();
1409
			case 't':
1410
				return ampmName.charAt(0).toLowerCase();
1411
			case 'tt':
1412
				return ampmName.toLowerCase();
1413
			default:
1414
				return match.replace(/'/g, "");
1415
			}
1416
		});
1417
1418
		return tmptime;
1419
	};
1420
1421
	/*
1422
	* the bad hack :/ override datepicker so it doesn't close on select
1423
	// inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378
1424
	*/
1425
	$.datepicker._base_selectDate = $.datepicker._selectDate;
1426
	$.datepicker._selectDate = function (id, dateStr) {
1427
		var inst = this._getInst($(id)[0]),
1428
			tp_inst = this._get(inst, 'timepicker'),
1429
			was_inline;
1430
1431
		if (tp_inst && inst.settings.showTimepicker) {
1432
			tp_inst._limitMinMaxDateTime(inst, true);
1433
			was_inline = inst.inline;
1434
			inst.inline = inst.stay_open = true;
1435
			//This way the onSelect handler called from calendarpicker get the full dateTime
1436
			this._base_selectDate(id, dateStr);
1437
			inst.inline = was_inline;
1438
			inst.stay_open = false;
1439
			this._notifyChange(inst);
1440
			this._updateDatepicker(inst);
1441
		} else {
1442
			this._base_selectDate(id, dateStr);
1443
		}
1444
	};
1445
1446
	/*
1447
	* second bad hack :/ override datepicker so it triggers an event when changing the input field
1448
	* and does not redraw the datepicker on every selectDate event
1449
	*/
1450
	$.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker;
1451
	$.datepicker._updateDatepicker = function (inst) {
1452
1453
		// don't popup the datepicker if there is another instance already opened
1454
		var input = inst.input[0];
1455
		if ($.datepicker._curInst && $.datepicker._curInst !== inst && $.datepicker._datepickerShowing && $.datepicker._lastInput !== input) {
1456
			return;
1457
		}
1458
1459
		if (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) {
1460
1461
			this._base_updateDatepicker(inst);
1462
1463
			// Reload the time control when changing something in the input text field.
1464
			var tp_inst = this._get(inst, 'timepicker');
1465
			if (tp_inst) {
1466
				tp_inst._addTimePicker(inst);
1467
			}
1468
		}
1469
	};
1470
1471
	/*
1472
	* third bad hack :/ override datepicker so it allows spaces and colon in the input field
1473
	*/
1474
	$.datepicker._base_doKeyPress = $.datepicker._doKeyPress;
1475
	$.datepicker._doKeyPress = function (event) {
1476
		var inst = $.datepicker._getInst(event.target),
1477
			tp_inst = $.datepicker._get(inst, 'timepicker');
1478
1479
		if (tp_inst) {
1480
			if ($.datepicker._get(inst, 'constrainInput')) {
1481
				var ampm = tp_inst.support.ampm,
1482
					tz = tp_inst._defaults.showTimezone !== null ? tp_inst._defaults.showTimezone : tp_inst.support.timezone,
1483
					dateChars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')),
1484
					datetimeChars = tp_inst._defaults.timeFormat.toString()
1485
											.replace(/[hms]/g, '')
1486
											.replace(/TT/g, ampm ? 'APM' : '')
1487
											.replace(/Tt/g, ampm ? 'AaPpMm' : '')
1488
											.replace(/tT/g, ampm ? 'AaPpMm' : '')
1489
											.replace(/T/g, ampm ? 'AP' : '')
1490
											.replace(/tt/g, ampm ? 'apm' : '')
1491
											.replace(/t/g, ampm ? 'ap' : '') + 
1492
											" " + tp_inst._defaults.separator + 
1493
											tp_inst._defaults.timeSuffix + 
1494
											(tz ? tp_inst._defaults.timezoneList.join('') : '') + 
1495
											(tp_inst._defaults.amNames.join('')) + (tp_inst._defaults.pmNames.join('')) + 
1496
											dateChars,
1497
					chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode);
1498
				return event.ctrlKey || (chr < ' ' || !dateChars || datetimeChars.indexOf(chr) > -1);
1499
			}
1500
		}
1501
1502
		return $.datepicker._base_doKeyPress(event);
1503
	};
1504
1505
	/*
1506
	* Fourth bad hack :/ override _updateAlternate function used in inline mode to init altField
1507
	* Update any alternate field to synchronise with the main field.
1508
	*/
1509
	$.datepicker._base_updateAlternate = $.datepicker._updateAlternate;
1510
	$.datepicker._updateAlternate = function (inst) {
1511
		var tp_inst = this._get(inst, 'timepicker');
1512
		if (tp_inst) {
1513
			var altField = tp_inst._defaults.altField;
1514
			if (altField) { // update alternate field too
1515
				var altFormat = tp_inst._defaults.altFormat || tp_inst._defaults.dateFormat,
1516
					date = this._getDate(inst),
1517
					formatCfg = $.datepicker._getFormatConfig(inst),
1518
					altFormattedDateTime = '', 
1519
					altSeparator = tp_inst._defaults.altSeparator ? tp_inst._defaults.altSeparator : tp_inst._defaults.separator, 
1520
					altTimeSuffix = tp_inst._defaults.altTimeSuffix ? tp_inst._defaults.altTimeSuffix : tp_inst._defaults.timeSuffix,
1521
					altTimeFormat = tp_inst._defaults.altTimeFormat !== null ? tp_inst._defaults.altTimeFormat : tp_inst._defaults.timeFormat;
1522
				
1523
				altFormattedDateTime += $.datepicker.formatTime(altTimeFormat, tp_inst, tp_inst._defaults) + altTimeSuffix;
1524
				if (!tp_inst._defaults.timeOnly && !tp_inst._defaults.altFieldTimeOnly && date !== null) {
1525
					if (tp_inst._defaults.altFormat) {
1526
						altFormattedDateTime = $.datepicker.formatDate(tp_inst._defaults.altFormat, date, formatCfg) + altSeparator + altFormattedDateTime;
1527
					}
1528
					else {
1529
						altFormattedDateTime = tp_inst.formattedDate + altSeparator + altFormattedDateTime;
1530
					}
1531
				}
1532
				$(altField).val( inst.input.val() ? altFormattedDateTime : "");
1533
			}
1534
		}
1535
		else {
1536
			$.datepicker._base_updateAlternate(inst);	
1537
		}
1538
	};
1539
1540
	/*
1541
	* Override key up event to sync manual input changes.
1542
	*/
1543
	$.datepicker._base_doKeyUp = $.datepicker._doKeyUp;
1544
	$.datepicker._doKeyUp = function (event) {
1545
		var inst = $.datepicker._getInst(event.target),
1546
			tp_inst = $.datepicker._get(inst, 'timepicker');
1547
1548
		if (tp_inst) {
1549
			if (tp_inst._defaults.timeOnly && (inst.input.val() !== inst.lastVal)) {
1550
				try {
1551
					$.datepicker._updateDatepicker(inst);
1552
				} catch (err) {
1553
					$.timepicker.log(err);
1554
				}
1555
			}
1556
		}
1557
1558
		return $.datepicker._base_doKeyUp(event);
1559
	};
1560
1561
	/*
1562
	* override "Today" button to also grab the time and set it to input field.
1563
	*/
1564
	$.datepicker._base_gotoToday = $.datepicker._gotoToday;
1565
	$.datepicker._gotoToday = function (id) {
1566
		var inst = this._getInst($(id)[0]);
1567
		this._base_gotoToday(id);
1568
		var tp_inst = this._get(inst, 'timepicker');
1569
		var tzoffset = $.timepicker.timezoneOffsetNumber(tp_inst.timezone);
1570
		var now = new Date();
1571
		now.setMinutes(now.getMinutes() + now.getTimezoneOffset() + tzoffset);
1572
		this._setTime(inst, now);
1573
		this._setDate(inst, now);
1574
		tp_inst._onSelectHandler();
1575
	};
1576
1577
	/*
1578
	* Disable & enable the Time in the datetimepicker
1579
	*/
1580
	$.datepicker._disableTimepickerDatepicker = function (target) {
1581
		var inst = this._getInst(target);
1582
		if (!inst) {
1583
			return;
1584
		}
1585
1586
		var tp_inst = this._get(inst, 'timepicker');
1587
		$(target).datepicker('getDate'); // Init selected[Year|Month|Day]
1588
		if (tp_inst) {
1589
			inst.settings.showTimepicker = false;
1590
			tp_inst._defaults.showTimepicker = false;
1591
			tp_inst._updateDateTime(inst);
1592
		}
1593
	};
1594
1595
	$.datepicker._enableTimepickerDatepicker = function (target) {
1596
		var inst = this._getInst(target);
1597
		if (!inst) {
1598
			return;
1599
		}
1600
1601
		var tp_inst = this._get(inst, 'timepicker');
1602
		$(target).datepicker('getDate'); // Init selected[Year|Month|Day]
1603
		if (tp_inst) {
1604
			inst.settings.showTimepicker = true;
1605
			tp_inst._defaults.showTimepicker = true;
1606
			tp_inst._addTimePicker(inst); // Could be disabled on page load
1607
			tp_inst._updateDateTime(inst);
1608
		}
1609
	};
1610
1611
	/*
1612
	* Create our own set time function
1613
	*/
1614
	$.datepicker._setTime = function (inst, date) {
1615
		var tp_inst = this._get(inst, 'timepicker');
1616
		if (tp_inst) {
1617
			var defaults = tp_inst._defaults;
1618
1619
			// calling _setTime with no date sets time to defaults
1620
			tp_inst.hour = date ? date.getHours() : defaults.hour;
1621
			tp_inst.minute = date ? date.getMinutes() : defaults.minute;
1622
			tp_inst.second = date ? date.getSeconds() : defaults.second;
1623
			tp_inst.millisec = date ? date.getMilliseconds() : defaults.millisec;
1624
			tp_inst.microsec = date ? date.getMicroseconds() : defaults.microsec;
1625
1626
			//check if within min/max times.. 
1627
			tp_inst._limitMinMaxDateTime(inst, true);
1628
1629
			tp_inst._onTimeChange();
1630
			tp_inst._updateDateTime(inst);
1631
		}
1632
	};
1633
1634
	/*
1635
	* Create new public method to set only time, callable as $().datepicker('setTime', date)
1636
	*/
1637
	$.datepicker._setTimeDatepicker = function (target, date, withDate) {
1638
		var inst = this._getInst(target);
1639
		if (!inst) {
1640
			return;
1641
		}
1642
1643
		var tp_inst = this._get(inst, 'timepicker');
1644
1645
		if (tp_inst) {
1646
			this._setDateFromField(inst);
1647
			var tp_date;
1648
			if (date) {
1649
				if (typeof date === "string") {
1650
					tp_inst._parseTime(date, withDate);
1651
					tp_date = new Date();
1652
					tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
1653
					tp_date.setMicroseconds(tp_inst.microsec);
1654
				} else {
1655
					tp_date = new Date(date.getTime());
1656
					tp_date.setMicroseconds(date.getMicroseconds());
1657
				}
1658
				if (tp_date.toString() === 'Invalid Date') {
1659
					tp_date = undefined;
1660
				}
1661
				this._setTime(inst, tp_date);
1662
			}
1663
		}
1664
1665
	};
1666
1667
	/*
1668
	* override setDate() to allow setting time too within Date object
1669
	*/
1670
	$.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker;
1671
	$.datepicker._setDateDatepicker = function (target, _date) {
1672
		var inst = this._getInst(target);
1673
		var date = _date;
1674
		if (!inst) {
1675
			return;
1676
		}
1677
1678
		if (typeof(_date) === 'string') {
1679
			date = new Date(_date);
1680
			if (!date.getTime()) {
1681
				this._base_setDateDatepicker.apply(this, arguments);
1682
				date = $(target).datepicker('getDate');
1683
			}
1684
		}
1685
1686
		var tp_inst = this._get(inst, 'timepicker');
1687
		var tp_date;
1688
		if (date instanceof Date) {
1689
			tp_date = new Date(date.getTime());
1690
			tp_date.setMicroseconds(date.getMicroseconds());
1691
		} else {
1692
			tp_date = date;
1693
		}
1694
		
1695
		// This is important if you are using the timezone option, javascript's Date 
1696
		// object will only return the timezone offset for the current locale, so we 
1697
		// adjust it accordingly.  If not using timezone option this won't matter..
1698
		// If a timezone is different in tp, keep the timezone as is
1699
		if (tp_inst && tp_date) {
1700
			// look out for DST if tz wasn't specified
1701
			if (!tp_inst.support.timezone && tp_inst._defaults.timezone === null) {
1702
				tp_inst.timezone = tp_date.getTimezoneOffset() * -1;
1703
			}
1704
			date = $.timepicker.timezoneAdjust(date, tp_inst.timezone);
1705
			tp_date = $.timepicker.timezoneAdjust(tp_date, tp_inst.timezone);
1706
		}
1707
1708
		this._updateDatepicker(inst);
1709
		this._base_setDateDatepicker.apply(this, arguments);
1710
		this._setTimeDatepicker(target, tp_date, true);
1711
	};
1712
1713
	/*
1714
	* override getDate() to allow getting time too within Date object
1715
	*/
1716
	$.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker;
1717
	$.datepicker._getDateDatepicker = function (target, noDefault) {
1718
		var inst = this._getInst(target);
1719
		if (!inst) {
1720
			return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
1721
		}
1722
1723
		var tp_inst = this._get(inst, 'timepicker');
1724
1725
		if (tp_inst) {
1726
			// if it hasn't yet been defined, grab from field
1727
			if (inst.lastVal === undefined) {
1728
				this._setDateFromField(inst, noDefault);
1729
			}
1730
1731
			var date = this._getDate(inst);
1732
			var currDT = $.trim((tp_inst.$altInput && tp_inst._defaults.altFieldTimeOnly) ? tp_inst.$input.val() + ' ' + tp_inst.$altInput.val() : tp_inst.$input.val());
1733
			if (date && tp_inst._parseTime(currDT, !inst.settings.timeOnly)) {
1734
				date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
1735
				date.setMicroseconds(tp_inst.microsec);
1736
1737
				// This is important if you are using the timezone option, javascript's Date 
1738
				// object will only return the timezone offset for the current locale, so we 
1739
				// adjust it accordingly.  If not using timezone option this won't matter..
1740
				if (tp_inst.timezone != null) {
1741
					// look out for DST if tz wasn't specified
1742
					if (!tp_inst.support.timezone && tp_inst._defaults.timezone === null) {
1743
						tp_inst.timezone = date.getTimezoneOffset() * -1;
1744
					}
1745
					date = $.timepicker.timezoneAdjust(date, tp_inst.timezone);
1746
				}
1747
			}
1748
			return date;
1749
		}
1750
		return this._base_getDateDatepicker(target, noDefault);
1751
	};
1752
1753
	/*
1754
	* override parseDate() because UI 1.8.14 throws an error about "Extra characters"
1755
	* An option in datapicker to ignore extra format characters would be nicer.
1756
	*/
1757
	$.datepicker._base_parseDate = $.datepicker.parseDate;
1758
	$.datepicker.parseDate = function (format, value, settings) {
1759
		var date;
1760
		try {
1761
			date = this._base_parseDate(format, value, settings);
1762
		} catch (err) {
1763
			// Hack!  The error message ends with a colon, a space, and
1764
			// the "extra" characters.  We rely on that instead of
1765
			// attempting to perfectly reproduce the parsing algorithm.
1766
			if (err.indexOf(":") >= 0) {
1767
				date = this._base_parseDate(format, value.substring(0, value.length - (err.length - err.indexOf(':') - 2)), settings);
1768
				$.timepicker.log("Error parsing the date string: " + err + "\ndate string = " + value + "\ndate format = " + format);
1769
			} else {
1770
				throw err;
1771
			}
1772
		}
1773
		return date;
1774
	};
1775
1776
	/*
1777
	* override formatDate to set date with time to the input
1778
	*/
1779
	$.datepicker._base_formatDate = $.datepicker._formatDate;
1780
	$.datepicker._formatDate = function (inst, day, month, year) {
1781
		var tp_inst = this._get(inst, 'timepicker');
1782
		if (tp_inst) {
1783
			tp_inst._updateDateTime(inst);
1784
			return tp_inst.$input.val();
1785
		}
1786
		return this._base_formatDate(inst);
1787
	};
1788
1789
	/*
1790
	* override options setter to add time to maxDate(Time) and minDate(Time). MaxDate
1791
	*/
1792
	$.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker;
1793
	$.datepicker._optionDatepicker = function (target, name, value) {
1794
		var inst = this._getInst(target),
1795
			name_clone;
1796
		if (!inst) {
1797
			return null;
1798
		}
1799
1800
		var tp_inst = this._get(inst, 'timepicker');
1801
		if (tp_inst) {
1802
			var min = null,
1803
				max = null,
1804
				onselect = null,
1805
				overrides = tp_inst._defaults.evnts,
1806
				fns = {},
1807
				prop,
1808
				ret,
1809
				oldVal,
1810
				$target;
1811
			if (typeof name === 'string') { // if min/max was set with the string
1812
				if (name === 'minDate' || name === 'minDateTime') {
1813
					min = value;
1814
				} else if (name === 'maxDate' || name === 'maxDateTime') {
1815
					max = value;
1816
				} else if (name === 'onSelect') {
1817
					onselect = value;
1818
				} else if (overrides.hasOwnProperty(name)) {
1819
					if (typeof (value) === 'undefined') {
1820
						return overrides[name];
1821
					}
1822
					fns[name] = value;
1823
					name_clone = {}; //empty results in exiting function after overrides updated
1824
				}
1825
			} else if (typeof name === 'object') { //if min/max was set with the JSON
1826
				if (name.minDate) {
1827
					min = name.minDate;
1828
				} else if (name.minDateTime) {
1829
					min = name.minDateTime;
1830
				} else if (name.maxDate) {
1831
					max = name.maxDate;
1832
				} else if (name.maxDateTime) {
1833
					max = name.maxDateTime;
1834
				}
1835
				for (prop in overrides) {
1836
					if (overrides.hasOwnProperty(prop) && name[prop]) {
1837
						fns[prop] = name[prop];
1838
					}
1839
				}
1840
			}
1841
			for (prop in fns) {
1842
				if (fns.hasOwnProperty(prop)) {
1843
					overrides[prop] = fns[prop];
1844
					if (!name_clone) { name_clone = $.extend({}, name); }
1845
					delete name_clone[prop];
1846
				}
1847
			}
1848
			if (name_clone && isEmptyObject(name_clone)) { return; }
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
1849
			if (min) { //if min was set
1850
				if (min === 0) {
1851
					min = new Date();
1852
				} else {
1853
					min = new Date(min);
1854
				}
1855
				tp_inst._defaults.minDate = min;
1856
				tp_inst._defaults.minDateTime = min;
1857
			} else if (max) { //if max was set
1858
				if (max === 0) {
1859
					max = new Date();
1860
				} else {
1861
					max = new Date(max);
1862
				}
1863
				tp_inst._defaults.maxDate = max;
1864
				tp_inst._defaults.maxDateTime = max;
1865
			} else if (onselect) {
1866
				tp_inst._defaults.onSelect = onselect;
1867
			}
1868
1869
			// Datepicker will override our date when we call _base_optionDatepicker when 
1870
			// calling minDate/maxDate, so we will first grab the value, call 
1871
			// _base_optionDatepicker, then set our value back.
1872
			if(min || max){
1873
				$target = $(target);
1874
				oldVal = $target.datetimepicker('getDate');
1875
				ret = this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value);
1876
				$target.datetimepicker('setDate', oldVal);
1877
				return ret;
1878
			}
1879
		}
1880
		if (value === undefined) {
1881
			return this._base_optionDatepicker.call($.datepicker, target, name);
1882
		}
1883
		return this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value);
1884
	};
1885
	
1886
	/*
1887
	* jQuery isEmptyObject does not check hasOwnProperty - if someone has added to the object prototype,
1888
	* it will return false for all objects
1889
	*/
1890
	var isEmptyObject = function (obj) {
1891
		var prop;
1892
		for (prop in obj) {
1893
			if (obj.hasOwnProperty(prop)) {
1894
				return false;
1895
			}
1896
		}
1897
		return true;
1898
	};
1899
1900
	/*
1901
	* jQuery extend now ignores nulls!
1902
	*/
1903
	var extendRemove = function (target, props) {
1904
		$.extend(target, props);
1905
		for (var name in props) {
1906
			if (props[name] === null || props[name] === undefined) {
1907
				target[name] = props[name];
1908
			}
1909
		}
1910
		return target;
1911
	};
1912
1913
	/*
1914
	* Determine by the time format which units are supported
1915
	* Returns an object of booleans for each unit
1916
	*/
1917
	var detectSupport = function (timeFormat) {
1918
		var tf = timeFormat.replace(/'.*?'/g, '').toLowerCase(), // removes literals
1919
			isIn = function (f, t) { // does the format contain the token?
1920
					return f.indexOf(t) !== -1 ? true : false;
1921
				};
1922
		return {
1923
				hour: isIn(tf, 'h'),
1924
				minute: isIn(tf, 'm'),
1925
				second: isIn(tf, 's'),
1926
				millisec: isIn(tf, 'l'),
1927
				microsec: isIn(tf, 'c'),
1928
				timezone: isIn(tf, 'z'),
1929
				ampm: isIn(tf, 't') && isIn(timeFormat, 'h'),
1930
				iso8601: isIn(timeFormat, 'Z')
1931
			};
1932
	};
1933
1934
	/*
1935
	* Converts 24 hour format into 12 hour
1936
	* Returns 12 hour without leading 0
1937
	*/
1938
	var convert24to12 = function (hour) {
1939
		hour %= 12;
1940
1941
		if (hour === 0) {
1942
			hour = 12;
1943
		}
1944
1945
		return String(hour);
1946
	};
1947
1948
	var computeEffectiveSetting = function (settings, property) {
1949
		return settings && settings[property] ? settings[property] : $.timepicker._defaults[property];
1950
	};
1951
1952
	/*
1953
	* Splits datetime string into date and time substrings.
1954
	* Throws exception when date can't be parsed
1955
	* Returns {dateString: dateString, timeString: timeString}
1956
	*/
1957
	var splitDateTime = function (dateTimeString, timeSettings) {
1958
		// The idea is to get the number separator occurrences in datetime and the time format requested (since time has
1959
		// fewer unknowns, mostly numbers and am/pm). We will use the time pattern to split.
1960
		var separator = computeEffectiveSetting(timeSettings, 'separator'),
1961
			format = computeEffectiveSetting(timeSettings, 'timeFormat'),
1962
			timeParts = format.split(separator), // how many occurrences of separator may be in our format?
1963
			timePartsLen = timeParts.length,
1964
			allParts = dateTimeString.split(separator),
1965
			allPartsLen = allParts.length;
1966
1967
		if (allPartsLen > 1) {
1968
			return {
1969
				dateString: allParts.splice(0, allPartsLen - timePartsLen).join(separator),
1970
				timeString: allParts.splice(0, timePartsLen).join(separator)
1971
			};
1972
		}
1973
1974
		return {
1975
			dateString: dateTimeString,
1976
			timeString: ''
1977
		};
1978
	};
1979
1980
	/*
1981
	* Internal function to parse datetime interval
1982
	* Returns: {date: Date, timeObj: Object}, where
1983
	*   date - parsed date without time (type Date)
1984
	*   timeObj = {hour: , minute: , second: , millisec: , microsec: } - parsed time. Optional
1985
	*/
1986
	var parseDateTimeInternal = function (dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
1987
		var date,
1988
			parts,
1989
			parsedTime;
1990
1991
		parts = splitDateTime(dateTimeString, timeSettings);
1992
		date = $.datepicker._base_parseDate(dateFormat, parts.dateString, dateSettings);
1993
1994
		if (parts.timeString === '') {
1995
			return {
1996
				date: date
1997
			};
1998
		}
1999
2000
		parsedTime = $.datepicker.parseTime(timeFormat, parts.timeString, timeSettings);
2001
2002
		if (!parsedTime) {
2003
			throw 'Wrong time format';
2004
		}
2005
2006
		return {
2007
			date: date,
2008
			timeObj: parsedTime
2009
		};
2010
	};
2011
2012
	/*
2013
	* Internal function to set timezone_select to the local timezone
2014
	*/
2015
	var selectLocalTimezone = function (tp_inst, date) {
2016
		if (tp_inst && tp_inst.timezone_select) {
2017
			var now = date || new Date();
2018
			tp_inst.timezone_select.val(-now.getTimezoneOffset());
2019
		}
2020
	};
2021
2022
	/*
2023
	* Create a Singleton Instance
2024
	*/
2025
	$.timepicker = new Timepicker();
2026
2027
	/**
2028
	 * Get the timezone offset as string from a date object (eg '+0530' for UTC+5.5)
2029
	 * @param {number} tzMinutes if not a number, less than -720 (-1200), or greater than 840 (+1400) this value is returned
2030
	 * @param {boolean} iso8601 if true formats in accordance to iso8601 "+12:45"
2031
	 * @return {string}
2032
	 */
2033
	$.timepicker.timezoneOffsetString = function (tzMinutes, iso8601) {
2034
		if (isNaN(tzMinutes) || tzMinutes > 840 || tzMinutes < -720) {
2035
			return tzMinutes;
2036
		}
2037
2038
		var off = tzMinutes,
2039
			minutes = off % 60,
2040
			hours = (off - minutes) / 60,
2041
			iso = iso8601 ? ':' : '',
2042
			tz = (off >= 0 ? '+' : '-') + ('0' + Math.abs(hours)).slice(-2) + iso + ('0' + Math.abs(minutes)).slice(-2);
2043
		
2044
		if (tz === '+00:00') {
2045
			return 'Z';
2046
		}
2047
		return tz;
2048
	};
2049
2050
	/**
2051
	 * Get the number in minutes that represents a timezone string
2052
	 * @param  {string} tzString formatted like "+0500", "-1245", "Z"
2053
	 * @return {number} the offset minutes or the original string if it doesn't match expectations
2054
	 */
2055
	$.timepicker.timezoneOffsetNumber = function (tzString) {
2056
		var normalized = tzString.toString().replace(':', ''); // excuse any iso8601, end up with "+1245"
2057
2058
		if (normalized.toUpperCase() === 'Z') { // if iso8601 with Z, its 0 minute offset
2059
			return 0;
2060
		}
2061
2062
		if (!/^(\-|\+)\d{4}$/.test(normalized)) { // possibly a user defined tz, so just give it back
2063
			return tzString;
2064
		}
2065
2066
		return ((normalized.substr(0, 1) === '-' ? -1 : 1) * // plus or minus
2067
					((parseInt(normalized.substr(1, 2), 10) * 60) + // hours (converted to minutes)
2068
					parseInt(normalized.substr(3, 2), 10))); // minutes
2069
	};
2070
2071
	/**
2072
	 * No way to set timezone in js Date, so we must adjust the minutes to compensate. (think setDate, getDate)
2073
	 * @param  {Date} date
2074
	 * @param  {string} toTimezone formatted like "+0500", "-1245"
2075
	 * @return {Date}
2076
	 */
2077
	$.timepicker.timezoneAdjust = function (date, toTimezone) {
2078
		var toTz = $.timepicker.timezoneOffsetNumber(toTimezone);
2079
		if (!isNaN(toTz)) {
2080
			date.setMinutes(date.getMinutes() + -date.getTimezoneOffset() - toTz);
2081
		}
2082
		return date;
2083
	};
2084
2085
	/**
2086
	 * Calls `timepicker()` on the `startTime` and `endTime` elements, and configures them to
2087
	 * enforce date range limits.
2088
	 * n.b. The input value must be correctly formatted (reformatting is not supported)
2089
	 * @param  {Element} startTime
2090
	 * @param  {Element} endTime
2091
	 * @param  {Object} options Options for the timepicker() call
2092
	 * @return {jQuery}
2093
	 */
2094
	$.timepicker.timeRange = function (startTime, endTime, options) {
2095
		return $.timepicker.handleRange('timepicker', startTime, endTime, options);
2096
	};
2097
2098
	/**
2099
	 * Calls `datetimepicker` on the `startTime` and `endTime` elements, and configures them to
2100
	 * enforce date range limits.
2101
	 * @param  {Element} startTime
2102
	 * @param  {Element} endTime
2103
	 * @param  {Object} options Options for the `timepicker()` call. Also supports `reformat`,
2104
	 *   a boolean value that can be used to reformat the input values to the `dateFormat`.
2105
	 * @param  {string} method Can be used to specify the type of picker to be added
2106
	 * @return {jQuery}
2107
	 */
2108
	$.timepicker.datetimeRange = function (startTime, endTime, options) {
2109
		$.timepicker.handleRange('datetimepicker', startTime, endTime, options);
2110
	};
2111
2112
	/**
2113
	 * Calls `datepicker` on the `startTime` and `endTime` elements, and configures them to
2114
	 * enforce date range limits.
2115
	 * @param  {Element} startTime
2116
	 * @param  {Element} endTime
2117
	 * @param  {Object} options Options for the `timepicker()` call. Also supports `reformat`,
2118
	 *   a boolean value that can be used to reformat the input values to the `dateFormat`.
2119
	 * @return {jQuery}
2120
	 */
2121
	$.timepicker.dateRange = function (startTime, endTime, options) {
2122
		$.timepicker.handleRange('datepicker', startTime, endTime, options);
2123
	};
2124
2125
	/**
2126
	 * Calls `method` on the `startTime` and `endTime` elements, and configures them to
2127
	 * enforce date range limits.
2128
	 * @param  {string} method Can be used to specify the type of picker to be added
2129
	 * @param  {Element} startTime
2130
	 * @param  {Element} endTime
2131
	 * @param  {Object} options Options for the `timepicker()` call. Also supports `reformat`,
2132
	 *   a boolean value that can be used to reformat the input values to the `dateFormat`.
2133
	 * @return {jQuery}
2134
	 */
2135
	$.timepicker.handleRange = function (method, startTime, endTime, options) {
2136
		options = $.extend({}, {
2137
			minInterval: 0, // min allowed interval in milliseconds
2138
			maxInterval: 0, // max allowed interval in milliseconds
2139
			start: {},      // options for start picker
2140
			end: {}         // options for end picker
2141
		}, options);
2142
2143
		// for the mean time this fixes an issue with calling getDate with timepicker()
2144
		var timeOnly = false;
2145
		if(method === 'timepicker'){
2146
			timeOnly = true;
2147
			method = 'datetimepicker';
2148
		}
2149
2150
		function checkDates(changed, other) {
2151
			var startdt = startTime[method]('getDate'),
2152
				enddt = endTime[method]('getDate'),
2153
				changeddt = changed[method]('getDate');
2154
2155
			if (startdt !== null) {
2156
				var minDate = new Date(startdt.getTime()),
2157
					maxDate = new Date(startdt.getTime());
2158
2159
				minDate.setMilliseconds(minDate.getMilliseconds() + options.minInterval);
2160
				maxDate.setMilliseconds(maxDate.getMilliseconds() + options.maxInterval);
2161
2162
				if (options.minInterval > 0 && minDate > enddt) { // minInterval check
2163
					endTime[method]('setDate', minDate);
2164
				}
2165
				else if (options.maxInterval > 0 && maxDate < enddt) { // max interval check
2166
					endTime[method]('setDate', maxDate);
2167
				}
2168
				else if (startdt > enddt) {
2169
					other[method]('setDate', changeddt);
2170
				}
2171
			}
2172
		}
2173
2174
		function selected(changed, other, option) {
2175
			if (!changed.val()) {
2176
				return;
2177
			}
2178
			var date = changed[method].call(changed, 'getDate');
2179
			if (date !== null && options.minInterval > 0) {
2180
				if (option === 'minDate') {
2181
					date.setMilliseconds(date.getMilliseconds() + options.minInterval);
2182
				}
2183
				if (option === 'maxDate') {
2184
					date.setMilliseconds(date.getMilliseconds() - options.minInterval);
2185
				}
2186
			}
2187
			
2188
			if (date.getTime) {
2189
				other[method].call(other, 'option', option, date);
2190
			}
2191
		}
2192
2193
		$.fn[method].call(startTime, $.extend({
2194
			timeOnly: timeOnly,
2195
			onClose: function (dateText, inst) {
2196
				checkDates($(this), endTime);
2197
			},
2198
			onSelect: function (selectedDateTime) {
2199
				selected($(this), endTime, 'minDate');
2200
			}
2201
		}, options, options.start));
2202
		$.fn[method].call(endTime, $.extend({
2203
			timeOnly: timeOnly,
2204
			onClose: function (dateText, inst) {
2205
				checkDates($(this), startTime);
2206
			},
2207
			onSelect: function (selectedDateTime) {
2208
				selected($(this), startTime, 'maxDate');
2209
			}
2210
		}, options, options.end));
2211
2212
		checkDates(startTime, endTime);
2213
		
2214
		selected(startTime, endTime, 'minDate');
2215
		selected(endTime, startTime, 'maxDate');
2216
2217
		return $([startTime.get(0), endTime.get(0)]);
2218
	};
2219
2220
	/**
2221
	 * Log error or data to the console during error or debugging
2222
	 * @param  {Object} err pass any type object to log to the console during error or debugging
2223
	 * @return {void}
2224
	 */
2225
	$.timepicker.log = function () {
2226
		if (window.console) {
2227
			window.console.log.apply(window.console, Array.prototype.slice.call(arguments));
2228
		}
2229
	};
2230
2231
	/*
2232
	 * Add util object to allow access to private methods for testability.
2233
	 */
2234
	$.timepicker._util = {
2235
		_extendRemove: extendRemove,
2236
		_isEmptyObject: isEmptyObject,
2237
		_convert24to12: convert24to12,
2238
		_detectSupport: detectSupport,
2239
		_selectLocalTimezone: selectLocalTimezone,
2240
		_computeEffectiveSetting: computeEffectiveSetting,
2241
		_splitDateTime: splitDateTime,
2242
		_parseDateTimeInternal: parseDateTimeInternal
2243
	};
2244
2245
	/*
2246
	* Microsecond support
2247
	*/
2248
	if (!Date.prototype.getMicroseconds) {
2249
		Date.prototype.microseconds = 0;
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type Date. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
2250
		Date.prototype.getMicroseconds = function () { return this.microseconds; };
2251
		Date.prototype.setMicroseconds = function (m) {
2252
			this.setMilliseconds(this.getMilliseconds() + Math.floor(m / 1000));
2253
			this.microseconds = m % 1000;
2254
			return this;
2255
		};
2256
	}
2257
2258
	/*
2259
	* Keep up with the version
2260
	*/
2261
	$.timepicker.version = "1.6.1";
2262
2263
}));
2264